home *** CD-ROM | disk | FTP | other *** search
/ CU Amiga Super CD-ROM 1 / CU Amiga Magazine CD-ROM Special Edition (1995)(EMAP Images)(GB)[Issue 1995-11].iso / Aminet / text / edit / WarpMail11.lha / WarpMail / source / funcs.c < prev    next >
C/C++ Source or Header  |  1995-05-20  |  11KB  |  442 lines

  1. /* -----------------------------------------------------------------------------
  2.  
  3.  ScanLib ©1995 Dietmar Eilert
  4.  
  5.  GoldED syntax parser example library (uses a syntax cache). Dice:
  6.  
  7.  DMAKE
  8.  
  9.  -------------------------------------------------------------------------------
  10.  
  11. */
  12.  
  13. #include "defs.h"
  14.  
  15. /// "Header stuff"
  16.  
  17. // Buffer handles are allocated for each text buffer to keep track of ressources:
  18.  
  19. struct BufferHandle {
  20.  
  21.     struct EditConfig     *bh_EditConfig;            // pointer to text data
  22.     struct GlobalConfig   *bh_GlobalConfig;          // editor configuration
  23.     struct SyntaxChunk    *bh_SyntaxStack;           // parser output
  24.     struct RefreshRequest  bh_RefreshRequest;        // display refresh request
  25. };
  26.  
  27. #define EMPTY_STACK ((struct SyntaxChunk *)~0)       // empty stack flag
  28.  
  29. ///
  30. /// "Prototype"
  31.  
  32. // library functions
  33.  
  34. Prototype LibCall struct ParserData     *MountScanner(void);
  35. Prototype LibCall ULONG                  StartScanner(__A0 struct GlobalConfig *, __A1 struct EditConfig *, __D0 struct SyntaxChunk *);
  36. Prototype LibCall ULONG                  CloseScanner(__D0 ULONG);
  37. Prototype LibCall void                   FlushScanner(__D0 ULONG);
  38. Prototype LibCall void                   SetupScanner(__A0 struct GlobalConfig  *);
  39. Prototype LibCall struct RefreshRequest *BriefScanner(__D0 ULONG, __A0 struct ScannerNotify *);
  40. Prototype LibCall struct SyntaxChunk    *ParseLine   (__D0 ULONG, __A0 struct LineNode *, __D1 ULONG);
  41. Prototype LibCall void                   UnparseLines(__A0 struct LineNode *, __D0 ULONG);
  42. Prototype LibCall void                   ParseSection(__D0 ULONG, __A0 struct LineNode *, __D1 ULONG);
  43.  
  44. // private functions
  45.  
  46. Prototype struct SyntaxChunk *ParseString(UBYTE *, UWORD, ULONG);
  47. Prototype struct SyntaxChunk *DupStack(struct SyntaxChunk *);
  48.  
  49. ///
  50. /// "Library functions"
  51.  
  52. /* ------------------------------- MountScanner --------------------------------
  53.  
  54.  Called by the editor before first usage of a scanner. Return a description of
  55.  our abilities.
  56.  
  57. */
  58.  
  59. LibCall struct ParserData *
  60. MountScanner()
  61. {
  62.     static struct ParserData parserData;
  63.  
  64.     // syntax elements understood by parser
  65.  
  66.     static UBYTE *levelNames[] = {
  67.  
  68.         "standard text",
  69.         "Quote level 1",
  70.         "Quote level 2",
  71.         "Quote level 3",
  72.         "Quote level 4",
  73.         "Quote level 5",
  74.         "Quote level 6",
  75.         "Quote level 7",
  76.         "Quote level 8",
  77.         "Quote level 9",
  78.         NULL
  79.     };
  80.  
  81.     // color suggestions
  82.  
  83.     static ULONG *levelColors[] = {
  84.  
  85.         MAKE_RGB4(0,  0,   0),
  86.         MAKE_RGB4(0,  15,  0),
  87.         MAKE_RGB4(15, 0,   0),
  88.         MAKE_RGB4(0,  0,  15),
  89.         MAKE_RGB4(15, 15, 15),
  90.         MAKE_RGB4(15, 15,  0),
  91.         MAKE_RGB4(0,  15, 15),
  92.         MAKE_RGB4(15,  0, 15),
  93.         MAKE_RGB4(0,  0,   0),
  94.         MAKE_RGB4(0,  15,  0),
  95.     };
  96.  
  97.     parserData.pd_Release  = SCANLIBVERSION;
  98.     parserData.pd_Version  = 1;
  99.     parserData.pd_Serial   = 0;
  100.     parserData.pd_Info     = "Warp Mail 1.1 ©'95 D.Eilert";
  101.     parserData.pd_Levels   = 10;
  102.     parserData.pd_Names    = levelNames;
  103.     parserData.pd_Colors   = levelColors;
  104.     parserData.pd_Flags    = SCPRF_SYNTAXCACHE;
  105.     parserData.pd_Reserved = 0;
  106.  
  107.     return(&parserData);
  108. }
  109.  
  110.  
  111. /* ------------------------------- StartScanner --------------------------------
  112.  
  113.  Called by the editor after a new text buffer has been created. We allocate a
  114.  buffer to hold text-specific data. The buffer address is returned as handle.
  115.  
  116. */
  117.  
  118. LibCall ULONG
  119. StartScanner(__A0 struct GlobalConfig *globalConfigPtr, __A1 struct EditConfig *editConfigPtr, __D0 struct SyntaxChunk *syntaxStack)
  120. {
  121.     struct BufferHandle *handle;
  122.  
  123.     if (handle = AllocVec(sizeof(struct BufferHandle), MEMF_PUBLIC | MEMF_CLEAR)) {
  124.  
  125.         handle->bh_GlobalConfig = globalConfigPtr;
  126.         handle->bh_EditConfig   = editConfigPtr;
  127.         handle->bh_SyntaxStack  = syntaxStack;
  128.     }
  129.  
  130.     return((ULONG)handle);
  131. }
  132.  
  133.  
  134. /* ------------------------------- CloseScanner --------------------------------
  135.  
  136.  Called by the editor if a text buffer is about to be closed. Deallocate buffer
  137.  specific 'global' data.
  138.  
  139. */
  140.  
  141. LibCall ULONG
  142. CloseScanner(__D0 ULONG scanID)
  143. {
  144.     if (scanID) {
  145.  
  146.         struct BufferHandle *handle = (struct BufferHandle *)scanID;
  147.  
  148.         FreeVec(handle);
  149.     }
  150.  
  151.     return(0);
  152. }
  153.  
  154.  
  155. /* ------------------------------- FlushScanner --------------------------------
  156.  
  157.  Called by the editor in low memory situations: we are supposed to free as much
  158.  memory as possible.
  159.  
  160. */
  161.  
  162. LibCall void
  163. FlushScanner(__D0 ULONG scanID)
  164. {
  165.     struct BufferHandle *handle;
  166.     struct EditConfig   *config;
  167.     struct LineNode     *lineNode;
  168.  
  169.     handle = (struct BufferHandle *)scanID;
  170.     config = handle->bh_EditConfig;
  171.  
  172.     if (lineNode = config->TextNodes)
  173.         UnparseLines(lineNode, config->Lines);
  174. }
  175.  
  176.  
  177. /* ------------------------------- SetupScanner --------------------------------
  178.  
  179.  Called by the editor if the user wants to change the scanner's configuration.
  180.  We do not support user configuration (parserData.pd_Flags: SCPRF_CONFIGWIN flag
  181.  unset).
  182.  
  183. */
  184.  
  185. LibCall void
  186. SetupScanner(__A0 globalConfigPtr)
  187. {
  188.     ;
  189. }
  190.  
  191.  
  192. /* ------------------------------- BriefScanner --------------------------------
  193.  
  194.  Called to notify a context scanner if lines have been added, deleted or
  195.  modified. We aren't a context scanner (parserData.pd_Flags: SCPRF_CONTEXT
  196.  flag unset), so we won't ever have to request additional display requests:
  197.  the editor's built-in refresh of damage regions is sufficient.
  198.  
  199. */
  200.  
  201. LibCall struct RefreshRequest *
  202. BriefScanner(__D0 ULONG scanID, __A0 struct ScannerNotify *notify)
  203. {
  204.     return(NULL);
  205. }
  206.  
  207.  
  208. /* --------------------------------- ParseLine ---------------------------------
  209.  
  210.  Parse a line, build a syntax description
  211.  
  212. */
  213.  
  214. LibCall struct SyntaxChunk *
  215. ParseLine(__D0 ULONG scanID, __A0 struct LineNode *lineNode, __D1 ULONG line)
  216. {
  217.     if (lineNode->Fold)
  218.  
  219.         return(NULL);
  220.  
  221.     else if (lineNode->Len) {
  222.  
  223.         // line not yet parsed ?
  224.  
  225.         if (lineNode->UserData == NULL) {
  226.  
  227.             struct SyntaxChunk *syntaxStack = ParseString(lineNode->Text, lineNode->Len, scanID);
  228.  
  229.             if (syntaxStack == EMPTY_STACK)
  230.                 lineNode->UserData = EMPTY_STACK;
  231.             else
  232.                 lineNode->UserData = DupStack(syntaxStack);
  233.         }
  234.  
  235.         if (lineNode->UserData == EMPTY_STACK)
  236.             return((struct SyntaxChunk *)NULL);
  237.         else
  238.             return((struct SyntaxChunk *)lineNode->UserData);
  239.     }
  240.     else
  241.         return(NULL);
  242. }
  243.  
  244. /* -------------------------------- UnparseLines -------------------------------
  245.  
  246.  Called by the editor if lines are to be deleted. We are supposed to free
  247.  private data attached to the lines.
  248.  
  249. */
  250.  
  251. LibCall void
  252. UnparseLines(__A0  struct LineNode *lineNode, __D0 ULONG lines)
  253. {
  254.     while (lines--) {
  255.  
  256.         // free syntax cache
  257.  
  258.         if (lineNode->UserData) {
  259.  
  260.             if (lineNode->UserData != (APTR)EMPTY_STACK)
  261.                 FreeVec((APTR)lineNode->UserData);
  262.  
  263.             lineNode->UserData = NULL;
  264.         }
  265.  
  266.         // free folded subblock
  267.  
  268.         if (lineNode->Fold)
  269.             UnparseLines(lineNode->Fold->TextNodes, lineNode->Fold->Lines);
  270.  
  271.         ++lineNode;
  272.     }
  273. }
  274.  
  275. /* -------------------------------- ParseSection -------------------------------
  276.  
  277.  Called by the editor if lines are to be displayed. The scanner is encouraged to
  278.  preparse the lines.
  279.  
  280. */
  281.  
  282. LibCall void
  283. ParseSection(__D0 ULONG scanID, __A0  struct LineNode *lineNode, __D1 ULONG lines)
  284. {
  285.     while (lines--) {
  286.  
  287.         // fold headers have to be ignored
  288.  
  289.         if (lineNode->Fold == NULL) {
  290.  
  291.             // line not yet parsed ?
  292.  
  293.             if (lineNode->Len)
  294.                 if (lineNode->UserData == NULL)
  295.                     lineNode->UserData = DupStack(ParseString(lineNode->Text, lineNode->Len, scanID));
  296.         }
  297.  
  298.         ++lineNode;
  299.     }
  300. }
  301.  
  302. ///
  303. /// "private"
  304.  
  305. /* -------------------------------- ParseString --------------------------------
  306.  
  307.  Parse a string, build a syntax description.
  308.  
  309. */
  310.  
  311. struct SyntaxChunk *
  312. ParseString(UBYTE *text, UWORD len, ULONG scanID)
  313. {
  314.     if (len) {
  315.  
  316.         struct SyntaxChunk *syntaxStack = ((struct BufferHandle *)scanID)->bh_SyntaxStack;
  317.  
  318.         BOOL  inString, ignoreNext;
  319.         UWORD userLevel, userStart, pos;
  320.  
  321.         // trailing spaces have to be ignored
  322.  
  323.         while (len && (text[len - 1] == 32))
  324.             --len;
  325.  
  326.         userLevel  = 0;
  327.         inString   = FALSE;
  328.         ignoreNext = FALSE;
  329.  
  330.         for (inString = FALSE, pos = 0; pos < len; ++pos) {
  331.  
  332.             if (text[pos] == 34)
  333.  
  334.                 inString = !inString;
  335.  
  336.             else if (text[pos] == '<')
  337.  
  338.                 ignoreNext = TRUE;
  339.  
  340.             else if (inString == FALSE) {
  341.  
  342.                 if (text[pos] == '>') {
  343.  
  344.                     if (ignoreNext)
  345.  
  346.                         ignoreNext = FALSE;
  347.  
  348.                     else if ((pos == 0) || (text[pos - 1] != '-')) {
  349.  
  350.                         UWORD quoteStart, quoteLen;
  351.  
  352.                         for (quoteStart = pos, quoteLen = 1; quoteStart && (text[quoteStart - 1] != '>'); --quoteStart)
  353.                             ++quoteLen;
  354.  
  355.                         // quote length beyond limit ?
  356.  
  357.                         if (quoteLen > 10)
  358.                             break;
  359.  
  360.                         // end of previous user ?
  361.  
  362.                         if (userLevel) {
  363.  
  364.                             syntaxStack[userLevel - 1].sc_Level = userLevel;
  365.                             syntaxStack[userLevel - 1].sc_Start = userStart;
  366.                             syntaxStack[userLevel - 1].sc_End   = quoteStart - 1;
  367.                         }
  368.  
  369.                         userStart = quoteStart;
  370.  
  371.                         if (++userLevel == 9)
  372.                             break;
  373.                     }
  374.                 }
  375.             }
  376.         }
  377.  
  378.         if (userLevel) {
  379.  
  380.             // terminate user
  381.  
  382.             syntaxStack[userLevel - 1].sc_Level = userLevel;
  383.             syntaxStack[userLevel - 1].sc_Start = userStart;
  384.             syntaxStack[userLevel - 1].sc_End   = len - 1;
  385.  
  386.             // terminate stack
  387.  
  388.             syntaxStack[userLevel].sc_Start = FALSE;
  389.             syntaxStack[userLevel].sc_End   = FALSE;
  390.             syntaxStack[userLevel].sc_Level = FALSE;
  391.  
  392.             return(syntaxStack);
  393.         }
  394.         else
  395.             return(EMPTY_STACK);
  396.     }
  397.  
  398.     return(EMPTY_STACK);
  399. }
  400.  
  401. /* --------------------------------- DupStack ----------------------------------
  402.  
  403.  Duplicate syntax stack (to be FreeVec'ed). Return NULL in case of failure.
  404.  
  405. */
  406.  
  407. struct SyntaxChunk *
  408. DupStack(syntaxStack)
  409.  
  410. struct SyntaxChunk *syntaxStack;
  411. {
  412.     if (syntaxStack && (syntaxStack != EMPTY_STACK)) {
  413.  
  414.         struct SyntaxChunk *chunk;
  415.         UWORD               elements;
  416.  
  417.         // determine stack size
  418.  
  419.         for (elements = 0, chunk = syntaxStack; chunk->sc_Level; ++chunk)
  420.             ++elements;
  421.  
  422.         // create copy of syntax stack (to be attached to a text line by the caller)
  423.  
  424.         if (elements) {
  425.  
  426.             ULONG size = (++elements) * sizeof(struct SyntaxChunk);
  427.  
  428.             chunk = syntaxStack;
  429.  
  430.             if (syntaxStack = AllocVec(size, MEMF_PUBLIC))
  431.                 movmem(chunk, syntaxStack, size);
  432.         }
  433.         else
  434.             syntaxStack = EMPTY_STACK;
  435.     }
  436.  
  437.     return(syntaxStack);
  438. }
  439.  
  440.  
  441. ///
  442.